#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
using namespace std;

bool quit = false; // 定义一个标记为
#define NUM 4

typedef void (*func_t)(const string &name, pthread_mutex_t *ptmx, pthread_cond_t *pcond); // 函数指针,指向每一个任务函数

class ThreadDate
{
public:
    ThreadDate(const string &name, func_t func, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
        : name_(name), func_(func), pmtx_(pmtx), pcond_(pcond)
    {
    }

public:
    string name_;
    func_t func_;
    pthread_mutex_t *pmtx_;
    pthread_cond_t *pcond_;
};

void func1(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        // wait一定要在加锁和解锁之间进行wait
        pthread_mutex_lock(pmtx);       // 对下面的代码进行加锁

        //线程进入阻塞状态，等待pthread_cond_signal(&cond)唤醒该线程，然后被唤醒后会立即执行
        pthread_cond_wait(pcond, pmtx); // 默认线程在执行的时候，wait代码被执行，当前线程就会被立即阻塞
        cout << name << "running---播放" << endl;
        pthread_mutex_unlock(pmtx);
    }
}
void func2(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        // wait一定要在加锁和解锁之间进行wait
        pthread_mutex_lock(pmtx);       // 对下面的代码进行加锁
        pthread_cond_wait(pcond, pmtx); // 默认线程在执行的时候，wait代码被执行，当前线程就会被立即阻塞
        cout << name << "running---下载" << endl;
        pthread_mutex_unlock(pmtx);
    }
}
void func3(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        // wait一定要在加锁和解锁之间进行wait
        pthread_mutex_lock(pmtx);       // 对下面的代码进行加锁
        
        pthread_cond_wait(pcond, pmtx); // 默认线程在执行的时候，wait代码被执行，当前线程就会被立即阻塞
        cout << name << "running---刷新" << endl;
        pthread_mutex_unlock(pmtx);
    }
}
void func4(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        // wait一定要在加锁和解锁之间进行wait
        pthread_mutex_lock(pmtx);       // 对下面的代码进行加锁
        pthread_cond_wait(pcond, pmtx); // 默认线程在执行的时候，wait代码被执行，当前线程就会被立即阻塞
        cout << name << "running---扫码用户信息" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *Entry(void *args)
{
    ThreadDate*td=(ThreadDate*)args;
    td->func_(td->name_,td->pmtx_,td->pcond_);
    delete td;
    return nullptr;
}
int main()
{
    pthread_mutex_t mtx;               // 定义一个锁
    pthread_cond_t cond;               //"条件变量"（让线程排队，一个一个拿锁，避免被一个线程频繁申请资源） 允许线程等待某个条件成立，并在条件成立时被唤醒
    pthread_mutex_init(&mtx, nullptr); // 初始化一个锁
    pthread_cond_init(&cond, nullptr); // 初始化“条件变量”

    // 创建线程
    pthread_t tids[NUM];

    func_t func[NUM] = {func1, func2, func3, func4}; // 函数指针数组

    for (int i = 0; i < NUM; i++)
    {
        string name = "Thread";
        name += to_string(i + 1).c_str();
        ThreadDate *td = new ThreadDate(name, func[i], &mtx, &cond);
        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }

    sleep(5); // 主线程

    int cnt = 10;
    while (cnt--)
    {
        cout << "resume thread run code..." << cnt << endl;
        // pthread_cond_broadcast(&code);唤醒等待在条件变量上的所有线程
        pthread_cond_signal(&cond); // 唤醒等待在条件变量上的一个线程
        sleep(1);
    }

    cout << "ctrl done" << endl;
    quit = true;
    pthread_cond_broadcast(&cond); // 唤醒所有条件变量下的所有线程

    for (int i = 0; i < NUM; i++)
    {
        pthread_join(tids[i], nullptr);
        cout << "thread:" << tids[i] << "quit" << endl;
    }

    pthread_mutex_destroy(&mtx); // 销毁锁
    pthread_cond_destroy(&cond); // 销毁条件变量

    return 0;
}